package com.jdd.fintech.morse.plugin.util;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.*;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.URLEncoder;
import java.util.*;

/**
 * @description: Http请求工具类
 * @credit: 2022-03-25 15:33
 * @author: fengcheng
 **/
public class HttpClientUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientUtil.class);

    private static final String URL_PARAM_CONNECT_FLAG = "&";

    public static final String URL_PARAM_CHARSET_UTF8 = "UTF-8"; // 定义编码格式 UTF-8

    public static final String URL_PARAM_CHARSET_GBK = "GBK"; // 定义编码格式 GBK

    public static final String CONTENT_TYPE = "application/json";

    public static final String CONTENT_TYPE_KEY = "Content-Type";

    private static final String EMPTY = "";

    private static MultiThreadedHttpConnectionManager connectionManager = null;

    private static int connectionTimeOut = 5000;

    private static int socketTimeOut = 30000;

    private static int maxConnectionPerHost = 20;

    private static int maxTotalConnections = 20;

    private static HttpClient client;

    static {
        connectionManager = new MultiThreadedHttpConnectionManager();
        connectionManager.getParams().setConnectionTimeout(connectionTimeOut);
        connectionManager.getParams().setSoTimeout(socketTimeOut);
        connectionManager.getParams().setDefaultMaxConnectionsPerHost(maxConnectionPerHost);
        connectionManager.getParams().setMaxTotalConnections(maxTotalConnections);
        client = new HttpClient(connectionManager);
    }

    /**
     * POST方式提交数据
     * @param url
     * @param body
     * @param charset
     * @param contentType
     * @return
     * @throws Exception
     */
    public static String sendPost(String url, String body, String charset, String contentType) throws Exception {
        StringBuffer response = new StringBuffer(EMPTY);
        InputStream inputStream = null;
        BufferedReader reader = null;
        PostMethod postMethod = new PostMethod(url);
        postMethod.setRequestHeader(CONTENT_TYPE_KEY, contentType + ";charset=" + charset);
        // 将要提交的数据放入postMethod中
        postMethod.setRequestBody(body);
        try {
            // 执行postMethod
            int statusCode = client.executeMethod(postMethod);
            if (statusCode == HttpStatus.SC_OK) {
                inputStream = postMethod.getResponseBodyAsStream();
                reader = new BufferedReader(new InputStreamReader(inputStream, postMethod.getResponseCharSet()));
                String inputLine = null;
                while ((inputLine = reader.readLine()) != null) {
                    response.append(inputLine);
                }
            } else {
                throw new Exception(url + "响应状态码 = " + postMethod.getStatusCode());
            }
        } catch (HttpException e) {
            LOGGER.error (url + "发生致命的异常，可能是协议不对或者返回的内容有问题", e);
            throw new HttpException(url + "发生致命的异常，可能是协议不对或者返回的内容有问题", e);
        } catch (IOException e) {
            LOGGER.error (url + "发生网络异常", e);
            throw new IOException(url + "发生网络异常", e);
        } catch (Exception e) {
            LOGGER.error (String.format("POST方式提交数据异常（%s）", e.getMessage()), e);
            throw new Exception(String.format("POST方式提交数据异常（%s）", e.getMessage()), e);
        } finally {
            if (reader != null) {
                reader.close();
            }
            if (inputStream != null) {
                inputStream.close();
            }
            if (postMethod != null) {
                postMethod.releaseConnection();
            }
        }
        return response.toString();
    }

    /**
     * GET方式提交数据
     * @param url
     * @param params
     * @param charset
     * @return
     */
    public static String sendGet(String url, Map<String, String> params, String charset) {
        if (StringUtils.isEmpty(charset)) {
            charset = URL_PARAM_CHARSET_UTF8;
        }
        String response = EMPTY;
        GetMethod getMethod = null;
        StringBuffer totalURL = new StringBuffer(EMPTY);

        if (url.indexOf("?") == -1) {
            totalURL.append(url).append("?").append(getUrl(params, charset));
        } else {
            totalURL.append(url).append("&").append(getUrl(params, charset));
        }
        LOGGER.debug("GET请求URL = \n" + totalURL.toString());

        try {
            getMethod = new GetMethod(totalURL.toString());
            getMethod.setRequestHeader(CONTENT_TYPE_KEY, "application/x-www-form-urlencoded;charset=" + charset);
            //执行getMethod
            int statusCode = client.executeMethod(getMethod);
            if (statusCode == HttpStatus.SC_OK) {
                response = getMethod.getResponseBodyAsString();
            } else {
                LOGGER.debug("响应状态码 = " + getMethod.getStatusCode());
            }
        } catch (HttpException e) {
            LOGGER.error("发生致命的异常，可能是协议不对或者返回的内容有问题", e);
        } catch (IOException e) {
            LOGGER.error("发生网络异常", e);
        } finally {
            if (getMethod != null) {
                getMethod.releaseConnection();
                getMethod = null;
            }
        }

        return response;
    }

    /**
     * 通用的请求方法
     * @param method 请求方法
     * @param url 请求地址
     * @param body 请求body，只有post、put方法支持
     * @param headers 请求头
     * @param headers 请求头
     * @return charset 指定返回数据的编码方式
     * @throws Exception
     */
    public static String request(String method, String url, String body, Map<String, String> headers, String charset) throws Exception{
        if (StringUtils.isEmpty(charset)) {
            charset = URL_PARAM_CHARSET_UTF8;
        }
        // 构造请求方法
        HttpMethod httpMethod = null;
        LOGGER.debug(method + "请求URL = \n" + url);
        if ("get".equalsIgnoreCase(method)) {
            httpMethod = new GetMethod(url);
        } else if ("post".equalsIgnoreCase(method)) {
            httpMethod = new PostMethod(url);
            ((PostMethod)httpMethod).setRequestBody(body);
        } else if ("put".equalsIgnoreCase(method)) {
            httpMethod = new PutMethod(url);
            ((PutMethod)httpMethod).setRequestBody(body);
        } else if ("delete".equalsIgnoreCase(method)) {
            httpMethod = new DeleteMethod(url);
        } else if ("head".equalsIgnoreCase(method)) {
            httpMethod = new HeadMethod(url);
        } else if ("options".equalsIgnoreCase(method)) {
            httpMethod = new OptionsMethod(url);
        } else {
            throw new UnsupportedOperationException("暂不支持" + method + "请求方法。");
        }

        if(headers != null && headers.size() != 0){
            for(Map.Entry<String,String> entry : headers.entrySet()) {
                httpMethod.addRequestHeader(entry.getKey(), entry.getValue());
            }
        }

        StringBuffer response = new StringBuffer(EMPTY);
        InputStream inputStream = null;
        BufferedReader reader = null;
        try {
            // 执行请求
            int statusCode = client.executeMethod(httpMethod);
            if (statusCode == HttpStatus.SC_OK) {
                inputStream = httpMethod.getResponseBodyAsStream();
                reader = new BufferedReader(new InputStreamReader(inputStream, charset));
                String inputLine = null;
                while ((inputLine = reader.readLine()) != null) {
                    response.append(inputLine);
                }
            } else {
                throw new Exception(url + "响应状态码 = " + httpMethod.getStatusCode());
            }
        } catch (HttpException e) {
            throw new HttpException(url + "发生致命的异常，可能是协议不对或者返回的内容有问题", e);
        } catch (IOException e) {
            throw new IOException(url + "发生网络异常", e);
        } catch (Exception e) {
            throw new Exception(String.format("%s方式提交数据异常（%s）", method, e.getMessage()), e);
        } finally {
            if (reader != null) {
                reader.close();
            }
            if (inputStream != null) {
                inputStream.close();
            }
            if (httpMethod != null) {
                httpMethod.releaseConnection();
            }
        }
        return response.toString();
    }

    /**
     * 根据Map生成URL字符串
     * @param map
     * @param charset
     * @return
     */
    private static String getUrl(Map<String, String> map, String charset) {
        if (null == map || map.keySet().size() == 0) {
            return EMPTY;
        }
        StringBuffer url = new StringBuffer();
        Set<String> keys = map.keySet();
        for (Iterator<String> it = keys.iterator(); it.hasNext();) {
            String key = it.next();
            if (map.containsKey(key)) {
                String val = map.get(key);
                String str = val != null ? val : EMPTY;
                try {
                    str = URLEncoder.encode(str, charset);
                } catch (UnsupportedEncodingException e) {
                    LOGGER.error("不支持的编码格式", e);
                }
                url.append(key).append("=").append(str).append(URL_PARAM_CONNECT_FLAG);
            }
        }
        String strURL = EMPTY;
        strURL = url.toString();
        if (URL_PARAM_CONNECT_FLAG.equals(EMPTY + strURL.charAt(strURL.length() - 1))) {
            strURL = strURL.substring(0, strURL.length() - 1);
        }

        return strURL;
    }

    public static Map<String, JSONObject> globelMap = Maps.newHashMap();

    public static void main(String[] args) {
        try {
            String client_id = "pahuipuclientid0000001";
            String url = "http://localhost:8888/dyBank/getRemoteAccessToken";
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("client_id", client_id);
            jsonObject.put("grant_type", "token");
            jsonObject.put("client_secret", "pahuipuclientsecret00000001");
            for (int i = 0; i < 2; i++) {
                String newClient_id = client_id+"_"+i;
                String resultJson = sendPost(url, jsonObject.toJSONString(), HttpClientUtil.URL_PARAM_CHARSET_UTF8, HttpClientUtil.CONTENT_TYPE);
                LOGGER.info("resultJson: {}" , resultJson);
                globelMap.put(newClient_id, JSONObject.parseObject(resultJson));
                Thread.sleep(200000);
            }
            System.out.println("");
            System.out.println("开始第二次测试循环");
            System.out.println("");
            String access_token = "";
            for (int i = 0; i < 2; i++) {
                String newClient_id = client_id+"_"+i;
                JSONObject globelMapObj = globelMap.get(newClient_id);
                if(ObjectUtils.isNotEmpty(globelMapObj)){
                    String time = globelMapObj.getString("time");
                    //加一个小时，到达token失效具体时间
                    Date date = DateUtils.addMinutes(PluginDateUtils.parseStr2Date(time), 10);
                    //通过token失效和当前时间进行比较，如果小于30分钟，则重新获取token，并记录到内存中
                    long mitime = 5L;
                    if(mitime <= getDateTimeDifference(PluginDateUtils.parseDate2Str(date))){
                        //需要重新发起获取token请求
                        System.out.println("Token过期时间已经过半，需要重新发起获取Token请求");
                        String resultJson = sendPost(url, jsonObject.toJSONString(), HttpClientUtil.URL_PARAM_CHARSET_UTF8, HttpClientUtil.CONTENT_TYPE);
                        LOGGER.info("resultJson: {}" , resultJson);
                        JSONObject value = JSONObject.parseObject(resultJson);
                        globelMap.put(newClient_id, value);
                        jsonObject = new JSONObject();
                        jsonObject = JSONObject.parseObject(value.getString("data"));
                    } else {
                        jsonObject = new JSONObject();
                        jsonObject = JSONObject.parseObject(globelMapObj.getString("data"));
                    }
                    access_token = jsonObject.getString("access_token");
                }
            }
            System.out.println("获取服务端token：" + access_token);
        } catch (Exception e) {
            System.out.println("发生异常：" + e.getMessage());
        }
    }

    /**
     * 获取时间差多少分钟
     * @param date
     */
    public static long getDateTimeDifference(String date) {
        long newTimeInMilli = 0L;
        try {
            Calendar calendar1 = Calendar.getInstance();
            Calendar calendar2 = Calendar.getInstance();
            calendar1.setTime(PluginDateUtils.parseStr2Date(date));
            System.out.println("开始时间：" + PluginDateUtils.formatDate(calendar1.getTime(), PluginDateUtils.str_yyyy_MM_dd_HH_mm_ss));
            calendar2.setTime(new Date());
            System.out.println("结束时间：" + PluginDateUtils.formatDate(calendar2.getTime(), PluginDateUtils.str_yyyy_MM_dd_HH_mm_ss));

            long timeInMilli1 = calendar1.getTimeInMillis();
            long timeInMilli2 = calendar2.getTimeInMillis();

            long timeInMilli = timeInMilli1 - timeInMilli2;
            newTimeInMilli = timeInMilli / 60 / 1000;
            System.out.println("相差：" + newTimeInMilli + "分钟");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return newTimeInMilli;
    }
}
